from io import BytesIO

from fastapi import APIRouter
from minio.error import S3Error
from typing import Dict

from seaman.core import JsonUtil

from common.method import *
from common.model import InterpolationData
from common.params import ReqSoftParams, SoftParams
from service.DataPreService import read_interpolation_data


router = APIRouter()
from model.soft.safe_cable_tension import run as safe_cable_run
from model.soft.descent_depth import run as descent_run


@router.post('/v3/safe/data')
async def safe_cable_data(params: ReqSoftParams):
    # 计算 MD5 哈希值
    md5_hash = params.calc_md5()
    # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取井号
    wellId: str = params.wellId
    # 获取间距
    space: float = params.space
    # 获取是否有造斜点
    is_slanting_point = params.is_slanting_point
    # 构建对象名称
    data_object_name = wellId + '/' + md5_hash + '-safe_cable.xlsx'
    # 构建可下入深度对象名称
    data_object_name_descent_depth = wellId + '/' + md5_hash + '-descent_depth.xlsx'
    print(data_object_name)
    # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
    is_Not_add_resistance = params.add_liquid_resistance
    try:
        client.stat_object('well', data_object_name_descent_depth)
        print('已存在对应可下入深度分析数据')
        file_data = client.get_object("well", data_object_name_descent_depth)
        df = pd.read_excel(BytesIO(file_data.read()))
        result_descent_depth = []
        for index, row in df.iterrows():
            result_descent_depth.append(row)
    except S3Error:
        print('不存在可下入深度分析分析数据')
        # 获取插值数据
        _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
        inc_depth: float = _list_[-1].depth
        # 获取给定的井斜角的值
        inc_value = params.inclination
        inc_dict: Dict = {}
        for item in _list_:
            inc_dict[item.depth] = item.inclination
            if item.inclination > inc_value:
                inc_depth = item.depth
                break
        print("当前的井斜角对应的深度为为", inc_depth)
        # 计算的间距
        calculate_space = params.calculate_space
        last_depth = _list_[-1].depth
        # 设置间隔深度列表
        desired_depths = [last_depth]
        # 从最后一个深度开始，减去间距，直到小于间距为止 这样就只计算部分深度
        while desired_depths[-1] > calculate_space:
            new_value = desired_depths[-1] - calculate_space
            desired_depths.append(new_value)
            # 对列表进行排序并去除重复值
        desired_depths = sorted(set(desired_depths), reverse=True)

        # 是否加入液体阻力 @TODO 如果为true就加入 否则加0
        is_Not_add_resistance = params.add_liquid_resistance
        # print(inc_dict)
        result_descent_depth = descent_run(soft_params, inc_depth, _list_, is_Not_add_resistance, desired_depths)
        save('well', data_object_name_descent_depth, result_descent_depth)
    try:
        client.stat_object('well', data_object_name)
        print('已存在对应安全操作时的缆头张力分析数据')
        file_data = client.get_object("well", data_object_name)
        df = pd.read_excel(BytesIO(file_data.read()))
        data_list = []
        for index, row in df.iterrows():
            data_list.append(row)
    except S3Error:
        print('不存在对应安全操作时的缆头张力分析数据')
    # 参数预处理
    soft_params: SoftParams = SoftParams(params)
    # 获取插值数据
    _list_: List[InterpolationData] = read_interpolation_data(wellId, space, is_slanting_point)
    inc_depth: float = _list_[-1].depth
    # ********************************************
    # # 拿到拦截的极限下入深度
    descent_depth_point: float = _list_[-1].depth
    # 是否可以下入到极限深度：井底 能下入就是 True 不能正常就是False
    is_not_descent_bottom: bool = True

    for descent_item in result_descent_depth:
        if descent_item.push_cable_pressure == 1:
            is_not_descent_bottom = False
            descent_depth_point = descent_item.depth
    # ********************************************
    # 首先加入最后一个值
    last_depth = _list_[-1].depth
    # 设置间隔
    interval: float = 150
    # 设置间隔深度列表---存放绞车操作表的井深
    desired_depths = [last_depth]
    # 加入 last_depth - params.calculate_space
    # 最后一个井深-间距（前端输入的间隔30米算一个还是间隔50米算一个）
    desired_depths.append(last_depth - params.calculate_space)

    current_depth = last_depth - params.calculate_space
    while current_depth > interval:
        new_value = current_depth - interval
        desired_depths.append(new_value)
        current_depth = new_value
    for depth_item in _list_:
        if (is_not_descent_bottom == False) and (depth_item.depth == descent_depth_point):
            desired_depths.append(depth_item.depth)

    # 对列表进行排序并去除重复值
    desired_depths = sorted(set(desired_depths), reverse=True)
    # 过滤掉小于 params.L1 的值
    desired_depths = [depth for depth in desired_depths if depth >= params.L1]
    print(desired_depths)
    print("************")

    # 获取给定的拉断力、置信度和安全操作拉力百分比
    operatingLoad: float = params.operatingLoad / 100
    # 将拉断力由千牛转换为牛
    F_break: float = params.F_break * 1000 * operatingLoad
    # F_break: float = params.F_break * 1000
    confidence_level: float = params.confidence_level
    # 井口摩擦力设置
    wellhead_friction: float = params.wellhead_friction
    # 上下限
    range_left: float = F_break * confidence_level - wellhead_friction
    range_right: float = F_break - wellhead_friction
    # 取值上下范围
    left: float = 0
    right: float = F_break - wellhead_friction
    mid: float = int((left + right) / 2)
    sc = {
        'depth': inc_depth
    }
    # if is_not_descent_bottom:
    #     sc['depth'] = inc_depth
    # else:
    #     sc['depth'] = descent_depth_point
    all_results = []  # 创建一个列表用于存储所有截断的结果
    while sc['depth'] >= params.L1:
        # 取值上下范围
        left: float = 0
        right: float = F_break - wellhead_friction
        # 中值计算
        while right >= left:
            mid: int = int((left + right) / 2)
            # print("mid取值:{}, left为:{} right为:{}".format(mid, left, right))
            # _list_ 根据当前深度截取 > sc[depth] 全部截取掉
            t_list = []
            for item in _list_:
                if(item.depth <= sc['depth']):
                    t_list.append(item)
            sc = safe_cable_run(soft_params, t_list, mid, desired_depths, wellhead_friction)
            if sc['result']:
                # print(JsonUtil.obj2str(sc['result']))
                # 将当前结果添加到列表中
                all_results.extend(sc['result'])
            if sc['ok']:
                break
            else:
                compare_val = sc['f_pull']
                # print("compare_val", compare_val)
                if compare_val > range_right:
                    right = mid - 1
                elif compare_val < range_left:
                    left = mid + 1

            # print(JsonUtil.obj2str(sc['result']))
    save('well', data_object_name, all_results)
    return all_results



